package cn.donting.web.desktop.plugin;

import org.apache.commons.compress.archivers.jar.JarArchiveEntry;
import org.springframework.boot.loader.tools.EntryWriter;
import org.springframework.boot.loader.tools.JarWriter;
import org.springframework.boot.loader.tools.Library;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;

public class AppJarWriter extends JarWriter {

    JarInputStream inputStream;

    public AppJarWriter(File file) throws FileNotFoundException, IOException {
        super(file);
    }


    @Override
    public void writeNestedLibrary(String location, Library library) throws IOException {
        super.writeNestedLibrary(location, library);
    }

//    public void writeLoaderClasses(File file) throws IOException {
//        URL loaderJar = file.toURI().toURL();
//        this.writeLoaderClasses(loaderJar);
//    }

    public void copyForBooJar(File file) throws IOException {
        URL loaderJar = file.toURI().toURL();
        this.writeLoaderClasses(loaderJar);
    }

    public void writeLoaderClasses(URL loaderJar) throws IOException {
        ArrayList<String> arrayList = new ArrayList<>();
        try (JarInputStream inputStream = new JarInputStream(new BufferedInputStream(loaderJar.openStream()))) {
            JarEntry entry;
            while ((entry = inputStream.getNextJarEntry()) != null) {
                if (entry.getName().endsWith(".jar")) {
                    continue;
                }
                writeEntry(entry.getName(), new InputStreamEntryWriter(inputStream));
            }
        }
    }

    private static class InputStreamEntryWriter implements EntryWriter {
        private static final int BUFFER_SIZE = 32 * 1024;

        private final InputStream inputStream;

        InputStreamEntryWriter(InputStream inputStream) {
            this.inputStream = inputStream;
        }

        @Override
        public void write(OutputStream outputStream) throws IOException {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = this.inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        }

    }

    private static class CrcAndSize {

        private final CRC32 crc = new CRC32();

        private long size;
        private static final int BUFFER_SIZE = 32 * 1024;


        CrcAndSize(InputStream inputStream) throws IOException {
            load(inputStream);
        }

        private void load(InputStream inputStream) throws IOException {
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                this.crc.update(buffer, 0, bytesRead);
                this.size += bytesRead;
            }
        }

        void setupStoredEntry(ZipEntry entry) {
            entry.setSize(this.size);
            entry.setCompressedSize(this.size);
            entry.setCrc(this.crc.getValue());
            entry.setMethod(ZipEntry.STORED);
        }

    }
}
